#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//redir
#define InputRedir 1
#define OutputRedir 2
#define AppendRedir 3
#define NoneRedir 0

int redir = 0;
char* filename = NULL;

#define NUM 1024
#define COUNT 64

char curWorkDir[NUM];
char pathVector[COUNT][NUM];
int posi = 0;
int lastcode = 0;

const char* getUser()
{
    char* user = getenv("USER");
    if (user)
        return user;
    else 
        return "none";
}

const char* getHostname()
{
    char* hostName = getenv("HOSTNAME");
    if (hostName)
        return hostName;
    else 
        return "none";
}

const char* getCwd()
{
    char* cwd = getenv("PWD");
    if (cwd)
        return cwd;
    else 
        return "none";
}

void GetUserCommand(char str[], int size)
{
    fgets(str, size, stdin);
    str[strlen(str) - 1] = '\0';
}

int UserCommandSplit(char str[], char* argv[])
{
    int argc = 0;
    argv[argc++] = strtok(str, " ");
    while (argv[argc++] = strtok(NULL, " "));

    return argc - 1;
}

void ExecuteCommand(char* argv[])
{

    pid_t id = fork();
    if (id == 0)
    {
        int fd = 0;
        if (redir == InputRedir)
        {
            fd = open(filename, O_RDONLY);
            dup2(fd, 0);
        }
        else if (redir == OutputRedir)
        {
            fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
            dup2(fd, 1);
        }
        else if (redir == AppendRedir) 
        {
            fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
            dup2(fd, 1);
        }
        else 
        {
            //do nothing
        }

        execvp(argv[0], argv);
        printf("-bash: %s: Command not found\n", argv[0]);
        exit(1);
    }
    else 
    {
        int status = 0;
        int ret = waitpid(id, &status, 0);
       
        lastcode = WEXITSTATUS(status);
    }
}

void Command_ls(char* argv[], int argc)
{
    if (strcmp(argv[0], "ls") == 0)
    {
        argv[argc++] = "--color=auto";
        argv[argc] = NULL;
    }
    
    if (strcmp(argv[0], "ll") == 0)
    {
        argv[0] = "ls";
        argv[argc++] = "--color=auto";
        argv[argc++] = "-l";
        argv[argc] = NULL;
    }
}

void cd(char* path)
{
    chdir(path);
    char temp[NUM];
    getcwd(temp, sizeof(temp));
    sprintf(curWorkDir, "PWD=%s", temp);
    putenv(curWorkDir);
}

int CheckBashCommand(char* argv[])
{
    if (strcmp(argv[0], "cd") == 0)
    {
        char* path = argv[1];
        if (argv[1] == NULL)
            path = "..";
        cd(path);
        return 1;
    }
    else if (strcmp(argv[0], "export") == 0)
    {
        if (argv[1] == NULL)
            return 1;
        strcpy(pathVector[posi], argv[1]);
        putenv(pathVector[posi]);
        posi += 1;
        
        printf("posi:%d\n", posi);
        return 1;
    }
    else if (strcmp(argv[0], "echo") == 0)
    {
        if (argv[1] == NULL)
        {
            printf("\n");
        }
        else if (argv[1][0] == '$' && strlen(argv[1]) == 1)
        {
            printf("$\n");
        }
        else if (argv[1][0] != '$')
        {
            printf("%s\n", argv[1]);
        }
        else 
        {
            char* val = argv[1] + 1;
            if (strcmp(val, "?") == 0)
            {
                printf("%d\n", lastcode);
            }
            else 
            {
                printf("%s\n", getenv(val));
            }
        }
        return 1;
    }

    return 0;
}

void SkipSpace(char** pos)
{
    while (**pos == ' ')
    {
        (*pos)++;
    }
}

void CheckRedir(char str[], int len)
{
    char* end = str + len - 1;
    char* start = str;

    while (end > start)
    {
        if (*end == '>')
        {
            if (*(end - 1) == '>')
            {
                //追加重定向
                *(end - 1) = '\0';
                filename = end + 1;
                SkipSpace(&filename);
                redir = AppendRedir;
                break;
            }
            else 
            {
                //输入重定向
                *(end) = '\0';
                filename = end + 1;
                SkipSpace(&filename);
                redir = OutputRedir;
                break;
            }
        }
        else if (*end == '<')
        {
            //输出重定向
            *end = '\0';
            filename = end + 1;
            SkipSpace(&filename);
            redir = InputRedir;
            break;
        }
        else 
        {
            end--;
        }
    }
}


int main()
{
    while (1)
    {
        redir = NoneRedir;
        filename = NULL;

        // 打印信息
        printf("[%s@%s %s]$ ", getUser(), getHostname(), getCwd() );
    
        //获取用户输入
        char str[1024];
        int size = sizeof(str);
        GetUserCommand(str, size);

        //判断是否有重定向内容
        CheckRedir(str, strlen(str));
    
        //将用户输入拆分成子串
        char* argv[COUNT];
        int argc = UserCommandSplit(str, argv);
        Command_ls(argv, argc);
   
        //判断所创建命令是否是内建命令
        int ret = CheckBashCommand(argv);
        if (ret == 1)
            continue;
        
        //创建子进程执行命令
        ExecuteCommand(argv);
    }

    return 0;
}
